/*
 * timer.c
 *
 *  Created on: Apr 16, 2015
 *      Author: mxw
 */
#include "timer.h"
#include <commlib.h>
#include <S3C2440addr.h>
#include <MainModu.h>
#include <LedDrv.h>

/*
 * INT_TIMER0(not used)         TOUT0 -> PmwDrv
 * INT_TIMER1->SimOS            TOUT1(not used)
 * INT_TIMER2->user timer       TOUT2(not used)
 * INT_TIMER3(not used)         TOUT3(not used)
 * INT_TIMER4(not used)         -(no pin)
 *
 * */

#define TIME2_INT_MASK (1 << 12)
#define TIME1_INT_MASK (1 << 11)

#define PRESCALER1_MASK (0xFF << 8)
#define MUX2_MASK (0xF << 8)
#define TIMER_MAX_CNT  (32)

#define ST_TIMER_INVILAD     0
#define ST_TIMER_SLEEP      1
#define ST_TIMER_ACTIVE     2

typedef struct {
    unsigned short      tid;
    unsigned char       st;
    ON_TIME_OUT_FUNC    fn;
    unsigned long       interval_in_ms;
    unsigned long       count_of_elapse;
} TIMER_ITEM;
TIMER_ITEM _timer_arr[TIMER_MAX_CNT];
static unsigned int _timer_ticker = 0;

void init_INT_TIMER1_for_simos() {
    //set INT_TIMER1's clcok frequency = PCLK / (prescaler0 + 1) / clock_devider = 50MHz/16/8=390625Hz
    //set prescaler1 as:15
    rTCFG0 &= ~0xff;
    rTCFG0 |= 15;           //prescaler1 = 15

    //set clock devider as 16
    rTCFG1 &= ~0xf0;
    rTCFG1 |= 2;            //mux1 = 1/8

    //set count buffer1 and count compare buffer1
    //rTCNTB1 = 39600; //10ms  39600*1000ms/396025=100ms
    rTCNTB1 = 3960; //10ms
    rTCMPB1 = 100;

    rTCON &= ~(0xF << 8);
    rTCON |= (0xB << 8);//auto load, update TCNTB1 TCMPB1, start Timer1
    rTCON &= ~(1 << 9); //clear manual bit.

    rINTMSK &= ~TIME1_INT_MASK; //clear INT_TIME1 mask
}

void init_timer() {
    int i = 0;
    memset(_timer_arr, 0, sizeof(_timer_arr));
    for (i = 0; i < TIMER_MAX_CNT; ++i) {
        _timer_arr[i].tid = i;
    }

    //init INT_TIME2
    //set INT_TIMER2's clcok frequency = PCLK / (prescaler1 + 1) / clock_devider = 50MHz/250/16=12500Hz
    //set prescaler1 as:249
    rTCFG0 &= ~PRESCALER1_MASK;
    rTCFG0 |= (249 << 8);

    //set clock devider as 16
    rTCFG1 &= ~MUX2_MASK;
    rTCFG1 |= (3 << 8);

    //set count buffer2 and count compare buffer2
    rTCNTB2 = 125; //10ms  12500/125=10ms
    rTCMPB2 = 100;


    rTCON &= ~(0xF << 12);
    rTCON |= (0xB << 12);//auto load, update TCNTB2 TCMPB2, start Timer2
    rTCON &= ~(1 << 13); //clear manual bit.

    rINTMSK &= ~TIME2_INT_MASK; //clear INT_TIME2 mask
}

unsigned short get_new_timer(ON_TIME_OUT_FUNC fn) {
    int i = 0;
    for (i = 0; i < TIMER_MAX_CNT; ++i) {
        if (ST_TIMER_INVILAD == _timer_arr[i].st) {
            _timer_arr[i].st = ST_TIMER_SLEEP;
            _timer_arr[i].fn = fn;
            _timer_arr[i].count_of_elapse = 0;
            return i;
        }
    }
    return ERR_TIMER_ID;
}

void delete_timer(unsigned short tid) {
    if (tid < TIMER_MAX_CNT) {
        _timer_arr[tid].st = ST_TIMER_INVILAD;
        _timer_arr[tid].count_of_elapse = 0;
        _timer_arr[tid].fn = 0;
    }
}

void start_timer(unsigned short tid, unsigned long interval_in_ms) {
    if (ST_TIMER_INVILAD != _timer_arr[tid].st) {
        _timer_arr[tid].interval_in_ms = interval_in_ms;
        _timer_arr[tid].st = ST_TIMER_ACTIVE;
    }
}

void stop_timer(unsigned short tid) {
    if (ST_TIMER_INVILAD != _timer_arr[tid].st) {
        _timer_arr[tid].count_of_elapse = 0;
        _timer_arr[tid].st = ST_TIMER_SLEEP;
    }
}

void on_timer_loop() {
    int i = 0;
    static CMsg msg;
    static int j = 0;
    ++_timer_ticker;
    ++j;
    if(j >= 100) {
        j = 0;
    }
    if(j < 80) {
        set_led(LED_4, LED_ON);
    } else {
        set_led(LED_4, LED_OFF);
    }

    for (i = 0; i < TIMER_MAX_CNT; ++i) {
        if (ST_TIMER_ACTIVE == _timer_arr[i].st) {
            _timer_arr[i].count_of_elapse += 10;
            if (_timer_arr[i].count_of_elapse >= _timer_arr[i].interval_in_ms) {
                if (0 != _timer_arr[i].fn) {
                    msg.msg_id = CMD_TIMER_TIMEOUT;
                    msg.data_len = 1;
                    msg.data[0] = i;
                    gMainMod.sendMsg(&gMainMod, &msg);

                    _timer_arr[i].count_of_elapse = 0;
                }
            }
        }
    }
}
unsigned int get_sys_ticker() { //10ms per tick
    return _timer_ticker;
}

void call_timer_func(unsigned short tid) {
    if (0 != _timer_arr[tid].fn) {
       _timer_arr[tid].fn(tid);
   }
}
